/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package vmwapplication.parser.solver;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import vmwapplication.data.IDAO;
import vmwapplication.data.Test;

/**
 *
 * @author marek
 */
public class NiedlemanWunschSolver implements Solver{
    
    private IDAO dao;
    
    private final int A=0, G=1, C=2, T=3;
   
    private final int d = -5;
                                   // A    G   C   T
    private final int[][] simularity = {{10, -1, -3, -4}, //A
                                        {-1,  7, -5, -3}, //G
                                        {-3, -5,  9,  0}, //C
                                        {-4, -3,  0,  8}};//T 
    
    public IDAO getDao() {
        return dao;
    }

    public void setDao(IDAO dao) {
        this.dao = dao;
    }

    public List<Result> solve(String dnaString) {
        List<Test> strings = dao.findAll();
        List<Result> results = new ArrayList<Result>();
        for(Test test : strings){
               int[][] fmatrix = computeFMatrix(test.getDnastring(), dnaString);
               Result result = getAlligment(test.getDnastring(), dnaString, fmatrix);
               if(result.getAligmentValue() >=0){
                results.add(result);
               }
        }
        Collections.sort(results);
        return results;
    }
    
    private Result getAlligment(String a, String b, int[][] fmatrix){
        String aligmentA ="";
        String aligmentB ="";
        String slashes = "";
        int i = a.length();
        int j = b.length();
        Integer aligmentValue = fmatrix[i][j];
        
        while(i > 0 && j > 0){
            int score = fmatrix[i][j];
            int scorediag = fmatrix[i-1][j-1];
            int scoreUp = fmatrix[i][j-1];
            int scoreLeft = fmatrix[i-1][j];
            
            if(score == (scorediag + sFunction(a.charAt(i-1), b.charAt(j-1)))){
                aligmentA = a.charAt(i-1) + aligmentA;
                aligmentB = b.charAt(j-1) + aligmentB;
                if(a.charAt(i-1) == b.charAt(j-1)){
                        slashes = "|" + slashes;
                    }else{
                        slashes = " " + slashes;
                    }
                i--;j--;
            }else if(score == (scoreLeft + d)){
                aligmentA = a.charAt(i-1) + aligmentA;
                aligmentB = "-" + aligmentB;
                slashes = " " + slashes;
                i--;
            }else if(score == (scoreUp + d)){
                aligmentA = "-" + aligmentA;
                aligmentB = b.charAt(j-1) + aligmentB;
                slashes = " " + slashes;
                j--;
            }
        }
        
        while(i > 0){
                aligmentA = a.charAt(i-1) + aligmentA;
                aligmentB = "-" + aligmentB;
                slashes = " " + slashes;
                i--;
            }
            
        while(j > 0){
            aligmentA = "-" + aligmentA;
            aligmentB = b.charAt(j-1) + aligmentB;
            slashes = " " + slashes;
            j--;
        }
        Result result = new Result(aligmentA, aligmentB,slashes, aligmentValue);
        return result;
    }
    
    private int[][] computeFMatrix(String stringA, String stringB){
        int lenghtA = stringA.length() +1;
        int lenghtB = stringB.length() +1;
        int[][] fMatrix = new int[lenghtA][lenghtB];
        for(int i=0; i<lenghtA-1; i++){
            fMatrix[i][0] = d*i;
        }
        
        for(int i=0; i<lenghtB-1; i++){
            fMatrix[0][i] = d*i;
        }
        
        for(int i=1;i<lenghtA;i++){
            for(int j=1;j<lenghtB;j++){
                int match = fMatrix[i-1][j-1] + sFunction(stringA.charAt(i-1), stringB.charAt(j-1));
                int delete = fMatrix[i-1][j] + d;
                int insert = fMatrix[i][j-1] + d;
                fMatrix[i][j] = max(match,delete,insert);
            }
        }
        return fMatrix;
    }
    
    private int sFunction(char A, char B){
        int aVal = translate(A);
        int bVal = translate(B);
        return simularity[aVal][bVal];
    }
    
    private int translate(char a){
        int i = 0;
        switch(a){
            case 'A':{i = A;}break;
            case 'G':{i = G;}break;
            case 'C':{i = C;}break;
            case 'T':{i = T;}break;
        }
        return i;
    }
    
    private int max(int a, int b, int c){
        int maxA = Math.max(a, b);
        return Math.max(maxA, c);
    
    }
    
}
